#include "stdafx.h"
#include "ThreadPool.h"
#include <process.h>

CThreadPool ThreadPool;

CThreadPool::CThreadPool()
{
	_threadsEaten = 0;
}


bool CThreadPool::ThreadExit(Thread * t)
{
	_mutex.Acquire();

	m_activeThreads.erase(t);

	if(_threadsToExit > 0)
	{
		--_threadsToExit;
		if(t->DeleteAfterExit)
			m_freeThreads.erase(t);

		_mutex.Release();
		delete t;
		return false;
	}


	// enter the "suspended" pool
	++_threadsEaten;
	std::set<Thread*>::iterator itr = m_freeThreads.find(t);

	if(itr != m_freeThreads.end())
	{

	}
	m_freeThreads.insert(t);

	_mutex.Release();

	return true;
}


void CThreadPool::ExecuteTask(ThreadBase * ExecutionTarget)
{

	Thread * t;
	_mutex.Acquire();
	--_threadsEaten;

	//get a thread from the thread pool
	if(m_freeThreads.size())//there are some threads available
	{    
		//get one thread
		t = *m_freeThreads.begin();
		//delete it from the free threads set
		m_freeThreads.erase(m_freeThreads.begin());

		//assign a job for the thread
		t->ExecutionTarget = ExecutionTarget;

		//let the thread do the job
		t->ControlInterface.Resume();
	}
	else
	{
		//start a new thread and do the job
		t = StartThread(ExecutionTarget);
	}

	//add the thread to the active threads set
	m_activeThreads.insert(t);
	_mutex.Release();


}

void CThreadPool::Startup()
{
	int i;
	int tcount = 5;

	for(i=0; i < tcount; ++i)
		StartThread(NULL);
}

void CThreadPool::ShowStats()
{
	_mutex.Acquire();

	//not implemented yet

	_mutex.Release();
}

void CThreadPool::KillFreeThreads(uint32 count)
{
	_mutex.Acquire();
	Thread * t;
	ThreadSet::iterator itr;
	uint32 i;
	for(i = 0, itr = m_freeThreads.begin(); i < count && itr != m_freeThreads.end(); ++i, ++itr)
	{
		t = *itr;
		t->ExecutionTarget = NULL; 
		t->DeleteAfterExit = true;
		++_threadsToExit;
		t->ControlInterface.Resume();
	}
	_mutex.Release();
}

void CThreadPool::Shutdown()
{
	_mutex.Acquire();
	size_t tcount = m_activeThreads.size() + m_freeThreads.size();        

	KillFreeThreads((uint32)m_freeThreads.size());
	_threadsToExit += (uint32)m_activeThreads.size();

	for(ThreadSet::iterator itr = m_activeThreads.begin(); itr != m_activeThreads.end(); ++itr)
	{
		if((*itr)->ExecutionTarget)
			(*itr)->ExecutionTarget->OnShutdown();
	}
	_mutex.Release();

	for(;;)
	{
		_mutex.Acquire();
		if(m_activeThreads.size() || m_freeThreads.size())
		{
			_mutex.Release();
			Sleep(1000);
			continue;
		}

		break;
	}
}


static unsigned long WINAPI thread_proc(void* param)
{
	Thread * t = (Thread*)param;
	t->SetupMutex.Acquire();
	uint32 tid = t->ControlInterface.GetId();
	bool ht = (t->ExecutionTarget != NULL);
	t->SetupMutex.Release();

	for(;;)
	{
		if(t->ExecutionTarget != NULL)
		{
			if(t->ExecutionTarget->Run())//do the job. if returned true, means the job is done
				delete t->ExecutionTarget;

			t->ExecutionTarget = NULL;
		}

		if(!ThreadPool.ThreadExit(t))
		{
			break;
		}
		else
		{
			t->ControlInterface.Suspend();//suspend the execution of the thread
		}
	}

	ExitThread(0);

	return 0;
}

Thread * CThreadPool::StartThread(ThreadBase * ExecutionTarget)
{
	HANDLE h;
	Thread * t = new Thread;

	t->DeleteAfterExit = false;
	t->ExecutionTarget = ExecutionTarget;
	t->SetupMutex.Acquire();
	/*
	CreateThread(
	lpThreadAttributes,	
	dwStackSize,
	lpStartAddress,
	lpParameter,
	dwCreationFlags,
	lpThreadId)
	*/
	h = CreateThread(NULL, 0, &thread_proc, (LPVOID)t, 0, (LPDWORD)&t->ControlInterface.thread_id);
	t->ControlInterface.Setup(h);
	t->SetupMutex.Release();

	return t;
}
